#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Fix Relative Paths in Database

This script updates existing databases to convert absolute file paths
to relative paths based on a chromium source directory.

Copyright 2024 Chromium Authors
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
"""

import sqlite3
import sys
import os
import argparse
from pathlib import Path


class RelativePathFixer:
    """Fixer for converting absolute paths to relative paths in database."""

    def __init__(self, db_path: str, chromium_dir: str):
        self.db_path = db_path
        self.chromium_dir = Path(chromium_dir).resolve()
        self.conn = None

    def connect(self):
        """Connect to the database."""
        self.conn = sqlite3.connect(self.db_path)
        self.conn.row_factory = sqlite3.Row

    def close(self):
        """Close database connection."""
        if self.conn:
            self.conn.close()

    def get_relative_path(self, file_path: str) -> str:
        """Convert absolute file path to relative path."""
        try:
            # Convert to Path object and make absolute
            abs_path = Path(file_path).resolve()

            # Get relative path from chromium directory
            rel_path = abs_path.relative_to(self.chromium_dir)

            # Convert to string with forward slashes for consistency
            return str(rel_path).replace(os.sep, '/')

        except ValueError:
            # If file is outside chromium directory, return original path
            print(f"Warning: File {file_path} is outside chromium directory, keeping original path")
            return file_path

    def analyze_current_paths(self):
        """Analyze current paths in the database."""
        cursor = self.conn.cursor()

        cursor.execute("""
            SELECT file_path, COUNT(*) as count
            FROM metrics
            GROUP BY file_path
            ORDER BY count DESC
            LIMIT 10
        """)

        print("Top 10 file paths by metric count:")
        print("-" * 60)
        for row in cursor.fetchall():
            print(f"{row['count']:6d} metrics: {row['file_path']}")

        # Check if paths are already relative
        cursor.execute("""
            SELECT COUNT(*) as total,
                   SUM(CASE WHEN file_path LIKE '/%' THEN 1 ELSE 0 END) as absolute_paths,
                   SUM(CASE WHEN file_path NOT LIKE '/%' THEN 1 ELSE 0 END) as relative_paths
            FROM metrics
        """)

        stats = cursor.fetchone()
        if stats:
            total = stats['total']
            absolute = stats['absolute_paths']
            relative = stats['relative_paths']
            print(f"\nPath Analysis:")
            print(f"  Total metrics: {total:,}")
            print(f"  Absolute paths: {absolute:,} ({absolute/total*100:.1f}%)")
            print(f"  Relative paths: {relative:,} ({relative/total*100:.1f}%)")

    def fix_all_paths(self, dry_run: bool = False):
        """Fix all file paths in the database."""
        cursor = self.conn.cursor()

        # Get all metrics with file paths
        cursor.execute("SELECT id, file_path FROM metrics WHERE file_path IS NOT NULL")
        metrics = cursor.fetchall()

        print(f"Processing {len(metrics)} metrics...")
        updated = 0
        skipped = 0

        for metric in metrics:
            metric_id = metric['id']
            original_path = metric['file_path']
            relative_path = self.get_relative_path(original_path)

            if original_path != relative_path:
                if not dry_run:
                    cursor.execute("""
                        UPDATE metrics
                        SET file_path = ?
                        WHERE id = ?
                    """, (relative_path, metric_id))
                updated += 1
            else:
                skipped += 1

            # Progress indicator
            if (updated + skipped) % 1000 == 0:
                print(f"  Processed {updated + skipped:,} metrics...")

        if not dry_run:
            self.conn.commit()

        print(f"\nPath Conversion Results:")
        print(f"  Metrics updated: {updated:,}")
        print(f"  Metrics skipped: {skipped:,}")
        print(f"  Total processed: {updated + skipped:,}")

    def verify_paths(self):
        """Verify that all paths are now relative."""
        cursor = self.conn.cursor()

        # Check for any remaining absolute paths
        cursor.execute("""
            SELECT COUNT(*) as count
            FROM metrics
            WHERE file_path IS NOT NULL AND file_path LIKE '/%'
        """)

        absolute_count = cursor.fetchone()[0]

        if absolute_count == 0:
            print("✅ All file paths are now relative!")
        else:
            print(f"⚠️  {absolute_count} metrics still have absolute paths")

        # Show some examples of relative paths
        cursor.execute("""
            SELECT DISTINCT file_path, COUNT(*) as count
            FROM metrics
            WHERE file_path IS NOT NULL AND file_path NOT LIKE '/%'
            GROUP BY file_path
            ORDER BY count DESC
            LIMIT 10
        """)

        print("\nTop 10 relative paths by metric count:")
        for row in cursor.fetchall():
            print(f"  {row['count']:6d} metrics: {row['file_path']}")


def main():
    """Main function."""
    parser = argparse.ArgumentParser(description='Fix absolute file paths to relative paths')
    parser.add_argument('--db', default='./uma_ukm_metrics.db',
                        help='Database file path')
    parser.add_argument('--chromium-dir', default='../../../',
                        help='Chromium source directory')
    parser.add_argument('--dry-run', action='store_true',
                        help='Show what would be changed without actually changing')
    parser.add_argument('--verify', action='store_true',
                        help='Verify that all paths are relative after fixing')
    parser.add_argument('--analyze', action='store_true',
                        help='Analyze current paths without making changes')

    args = parser.parse_args()

    if not Path(args.db).exists():
        print(f"Database file not found: {args.db}")
        print("Please run uma_ukm_extractor.py first to create the database.")
        sys.exit(1)

    chromium_dir = os.path.abspath(args.chromium_dir)
    if not os.path.isdir(chromium_dir):
        print(f"Chromium directory not found: {chromium_dir}")
        sys.exit(1)

    print(f"Database: {args.db}")
    print(f"Chromium directory: {chromium_dir}")

    fixer = RelativePathFixer(args.db, chromium_dir)
    fixer.connect()

    try:
        if args.analyze:
            fixer.analyze_current_paths()

        if args.verify:
            fixer.verify_paths()

        if not args.analyze and not args.verify:
            fixer.analyze_current_paths()

            if args.dry_run:
                print("\n" + "="*60)
                print("🔍 DRY RUN MODE - No changes will be made")
                print("="*60)

            fixer.fix_all_paths(dry_run=args.dry_run)

            if not args.dry_run:
                print("\n" + "="*60)
                print("✅ PATH CONVERSION COMPLETED")
                print("="*60)

                fixer.verify_paths()

    except Exception as e:
        print(f"Error: {e}")
        import traceback
        traceback.print_exc()

    finally:
        fixer.close()


if __name__ == '__main__':
    main()